<?php


namespace App\Services;


use App\Models\Menu;
use App\Utils\Code;
use App\Utils\Tree;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;

class MenuService extends BaseService
{
    /**
     * 创建数据
     * @param array $params
     * @return \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Model|object|null
     * @throws \Exception
     */
    public function store(array $params) {
        if (!$this->checkParams($params)){
            throw new \Exception('请求参数验证不通过', Code::PARAMETER_ERROR);
        }
        $model = new Menu();
        if (isset($params['pid']) && is_numeric($params['pid'])){
            if ($params['pid'] && !$this->show($params['pid'], false)){
                throw new \Exception('不存在的上级ID主键', Code::PARAMETER_ERROR);
            }
            $model->pid = $params['pid'];
        }
        if (Menu::where('title', $params['title'])->where('pid', $model->pid)->first()) {
            throw new \Exception('该菜单已经存在', Code::EXIST_REPEAT);
        }
        $model->title = $params['title'];
        if (isset($params['component']) && $params['component']) {
            $model->component = $params['component'];
        }
        if (isset($params['name']) && $params['name']) {
            $model->name = $params['name'];
        }
        if (isset($params['path']) && $params['path']) {
            $model->path = $params['path'];
        }
        if (isset($params['meta']) && $params['meta']) {
            $model->meta = $params['meta'];
        }
        if (isset($params['permission']) && $params['permission']) {
            $model->permission = $params['permission'];
        }
        if (isset($params['type']) && is_numeric($params['type'])) {
            $model->type = $params['type'];
        }
        if (isset($params['sort']) && is_numeric($params['sort'])){
            $model->sort = (int)$params['sort'];
        }
        if (isset($params['status']) && is_numeric($params['status'])){
            $model->status = (int)$params['status'];
        }
        return $model->save();
    }

    /**
     * 数据信息
     * @param $id
     * @param bool $simple
     * @param bool $abnormal
     * @return \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Model|object|null
     * @throws \Exception
     */
    public function show($id, $abnormal = true) {
        $model = Menu::find($id);
        if (!$model && $abnormal){
            throw new \Exception('不存在的菜单ID主键', Code::EMPTY_DATA);
        }
        return $model;
    }

    /**
     * 更新数据
     * @param $id
     * @param array $params
     * @return \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Model|object|null
     * @throws \Exception
     */
    public function update($id, array $params) {
        if (!$this->checkParams($params, true)){
            throw new \Exception('请求参数验证不通过', Code::PARAMETER_ERROR);
        }
        
        $model = $this->show($id);
        if (isset($params['pid']) && is_numeric($params['pid'])) {
            $menuList = Menu::get()->toArray();
            $model->pid = $params['pid'];
            if ($model->pid && in_array($model->pid, Tree::instance()->toChildrenId($model->id, 'id', $menuList))){
                throw new \Exception('上级主键非法', Code::LACK_OF_CONDITIONS);
            } elseif ($model->pid && !$this->show($model->pid)) {
                throw new \Exception('不存在的上级ID主键', Code::PARAMETER_ERROR);
            }
        }
        if (isset($params['title']) && $params['title']) {
            $model->title = $params['title'];
        }
        if (isset($params['component'])) {
            $model->component = $params['component'];
        }
        if (isset($params['name'])) {
            $model->name = $params['name'];
        }
        if (isset($params['path'])) {
            $model->path = $params['path'];
        }
        if (isset($params['meta'])) {
            $model->meta = $params['meta'];
        }
        if (isset($params['permission'])) {
            $model->permission = $params['permission'];
        }
        if (isset($params['type']) && is_numeric($params['type'])) {
            $model->type = $params['type'];
        }
        if (isset($params['sort']) && is_numeric($params['sort'])) {
            $model->sort = $params['sort'];
        }
        if (isset($params['status']) && is_numeric($params['status'])) {
            $model->status = $params['status'];
        }
        return $model->save();
    }

    /**
     * 删除数据
     * @param $id
     * @return mixed
     * @throws \Throwable
     */
    public function destroy($id) {
        if (!$this::$admin) {
            throw new \Exception('你没有权限删除节点', Code::LACK_OF_CONDITIONS);
        }
        if (Menu::where('pid', $id)->exists()) {
            throw new \Exception('该层级下包含有子级元素', Code::LACK_OF_CONDITIONS);
        }
        $model = $this->show($id);
        return DB::transaction(function () use ($model) {
            DB::table('bind_role_menu')->where('menu_id', $model->id)->delete();
            return $model->delete();
        });
    }

    /**
     * 数据列表
     * @param array $params
     * @return array
     */
    public function lists(array $params = []) {
        $lists = Menu::orderBy('sort', 'asc')->get()->toArray();
        if (isset($params['format']) && $params['format'] == 'list'){
            $lists = Tree::instance()->treeFormat($lists, 'children', null);
        } else {
            $lists = Tree::instance()->toTree($lists, 'id');
        }
        return $lists;
    }

    /**
     * 验证参数
     * @param array $params
     * @param bool $isUpdate
     * @return array
     * @throws \Exception
     */
    private function checkParams(array $params, $isUpdate = false){
        $rules = [
            'title' => ['bail', 'required', 'string', 'between:1,20'],
            'component ' => ['bail', 'nullable', 'string', 'between:1,50'],
            'name' => ['bail', 'nullable', 'string', 'between:1,50'],
            'path' => ['bail', 'nullable', 'string', 'between:1,200'],
            'pid' => ['bail', 'nullable', 'integer'],
            'type' => ['bail', 'nullable', 'integer', 'in:0,1'],
            'status' => ['bail', 'nullable', 'integer', 'in:0,1']
        ];
        if ($isUpdate){
            // 删除必选条件
            foreach ($rules as $field => &$rule){
                if (isset($rule[1]) && $rule[1] == 'required') {
                    $rule[1] = 'nullable';
                }
            }
        }
        $validator = Validator::make($params, $rules, [], [
            'title' => '菜单标题',
            'component' => '对应组件',
            'name' => '组件名称',
            'path' => '路由',
            'pid' => '上级菜单',
            'type' => '菜单类型',
            'status' => '可用状态'
        ]);
        if ($validator->fails()) {
            throw new \Exception($validator->errors()->first(), Code::PARAMETER_ERROR);
        }
        return $params;
    }
}
